export async function* mergeSort(array, compare, swap, set, left = 0, right = array.length - 1) {
    if (left < right) {
        const mid = Math.floor((left + right) / 2);
        
        yield* mergeSort(array, compare, swap, set, left, mid);
        yield* mergeSort(array, compare, swap, set, mid + 1, right);
        yield* merge(array, compare, swap, set, left, mid, right);
    } else if (left === right) {
        yield { type: 'complete' };
    }
}

async function* merge(array, compare, swap, set, left, mid, right) {
    const leftArray = [];
    const rightArray = [];
    
    for (let i = left; i <= mid; i++) {
        leftArray.push(array[i]);
    }
    
    for (let i = mid + 1; i <= right; i++) {
        rightArray.push(array[i]);
    }
    
    let i = 0, j = 0, k = left;
    
    while (i < leftArray.length && j < rightArray.length) {
        yield { type: 'compare', indices: [left + i, mid + 1 + j] };
        
        if (await compare(left + i, mid + 1 + j, leftArray[i], rightArray[j])) {
            array[k++] = leftArray[i++];
        } else {
            array[k++] = rightArray[j++];
        }
        
        yield { type: 'set', index: k - 1, value: array[k - 1] };
    }
    
    while (i < leftArray.length) {
        array[k++] = leftArray[i++];
        yield { type: 'set', index: k - 1, value: array[k - 1] };
    }
    
    while (j < rightArray.length) {
        array[k++] = rightArray[j++];
        yield { type: 'set', index: k - 1, value: array[k - 1] };
    }
    
    yield { type: 'complete' };
}